package gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.border.TitledBorder;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYDataset;

import parsing.InvalidFunctionException;
import parsing.Parser;

import core.InterpolatingMethod;
import core.LagrangeMethod;
import core.Method;
import core.NewtonDividedDifferences;
import core.Point;
import functions.Function;

public class Interpolator extends JFrame {

	private JPanel contentPane;
	private DefaultXYDataset dataset = new DefaultXYDataset();
	private ArrayList<Point> points = new ArrayList<Point>();
	private double[][] interpolatedFunction;
	private double[][] originalFunction;
	private String method;
	public static Interpolator gui;
	private File file;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Interpolator frame = new Interpolator("");
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public Interpolator(final String method) {
		setUndecorated(true);
		setBounds(100, 100, 672, 501);
		contentPane = new JPanel();
		contentPane.setBorder(new TitledBorder(null, "Numerical Beast",
				TitledBorder.CENTER, TitledBorder.ABOVE_TOP, null, null));
		contentPane.setBackground(Color.lightGray);
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		
		this.method = method;

		JFreeChart chart = ChartFactory.createXYLineChart(
				"Interpolating", // The chart title
				"X", // x axis label
				"Y", // y axis label
				dataset, // The dataset for the chart
				PlotOrientation.VERTICAL, true, // Is a legend required?
				false, // Use tooltips
				false // Configure chart to generate URLs?
				);
		final ChartPanel cp = new ChartPanel(chart);
		cp.setLocation(10, 26);
		cp.setSize(490, 420);
		getContentPane().add(cp);
		
		final JTextPane textPane = new JTextPane();
		textPane.setBounds(510, 159, 136, 249);
		contentPane.add(textPane);

		JButton btnNewButton = new JButton("Add Point");

		btnNewButton.setBounds(510, 23, 136, 23);
		contentPane.add(btnNewButton);

		JButton btnNewButton_1 = new JButton("Load File");
		btnNewButton_1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					JFileChooser chooser = new JFileChooser();
					String url = "";
					int returnVal = chooser.showOpenDialog(chooser);
					if (returnVal == JFileChooser.APPROVE_OPTION) {
						url = chooser.getSelectedFile().getPath();
					}
					file = new File(url);
					Scanner scanner = new Scanner(file);
					while (scanner.hasNext()) {
						String s = scanner.nextLine();
						String[] a = s.split(",");
						Point p = new Point(Double.parseDouble(a[0]),Double.parseDouble(a[1]));
						points.add(p);
						textPane.setText(textPane.getText() + "\n" + "(" + s + ")");
					}
				} catch (Exception e1) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null,"Invalid File");
				}
			}
		});
		btnNewButton_1.setBounds(510, 57, 136, 23);
		contentPane.add(btnNewButton_1);

		JButton btnNewButton_2 = new JButton("Interpolate");
		btnNewButton_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				Point po[] = new Point[points.size()];
				points.toArray(po);

				double maxX = Double.MIN_VALUE;
				double minX = Double.MAX_VALUE;

				double step = 0.1;

				for (int i = 0; i < po.length; i++) {
					minX = Math.min(po[i].getX(), minX);
					maxX = Math.max(po[i].getX(), maxX);
				}

				minX -= 1;
				maxX += 1;

				interpolatedFunction = new double[2][(int) ((maxX - minX) / step)];
				InterpolatingMethod lM;
				if (method.equals("l"))
					lM = new LagrangeMethod();
				else if (method.equals("d"))
					lM = new NewtonDividedDifferences();
				else
					lM = new NewtonDividedDifferences();
				long start,end;
				start = System.nanoTime();
				Function fn = lM.run(po);
				end = System.nanoTime();
				int i = 0;
				for (double x = minX; x <= maxX
						&& i < interpolatedFunction[0].length; x += step, i++) {
					interpolatedFunction[0][i] = x;
					interpolatedFunction[1][i] = fn.eval(x);
				}
				
				dataset.addSeries("Interpolated Function", interpolatedFunction);
				JOptionPane.showMessageDialog(null,
						 "finished at " + (end - start) +" ms");

			}
		});
		btnNewButton_2.setBounds(510, 91, 136, 23);
		contentPane.add(btnNewButton_2);

		JButton button = new JButton("Simulate");
		button.setBounds(506, 417, 140, 29);
		contentPane.add(button);

		JButton button_1 = new JButton("<");
		button_1.setBounds(510, 449, 64, 29);
		contentPane.add(button_1);

		JButton button_2 = new JButton(">");
		button_2.setBounds(586, 449, 64, 29);
		contentPane.add(button_2);

		

		JButton button_3 = new JButton("Back");
		button_3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Main.main.setVisible(true);
				dispose();
			}
		});
		button_3.setBounds(10, 449, 93, 29);
		contentPane.add(button_3);

		JButton button_4 = new JButton("Exit");
		button_4.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		button_4.setBounds(111, 449, 93, 29);
		contentPane.add(button_4);

		JButton btnOrginalFunction = new JButton("Orginal Function");
		btnOrginalFunction.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
					String fun = JOptionPane.showInputDialog(
							"Enter the original function", "");
					Parser p = new Parser();
					Function f = p.parse(fun);
					originalFunction = new double[2][interpolatedFunction[0].length];
					for (int i = 0; i < interpolatedFunction[0].length; i++) {
						originalFunction[0][i] = interpolatedFunction[0][i];
						originalFunction[1][i] = f
								.eval(interpolatedFunction[0][i]);
					}
					dataset.addSeries("Original Function", originalFunction);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					JOptionPane.showMessageDialog(null, e.getMessage());
					return;
				}
			}
		});
		btnOrginalFunction.setBounds(510, 125, 136, 23);
		contentPane.add(btnOrginalFunction);

		final JButton btnFullScreen = new JButton("Full Screen");
		btnFullScreen.setBounds(357, 452, 106, 23);
		contentPane.add(btnFullScreen);
		btnFullScreen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setExtendedState(JFrame.MAXIMIZED_BOTH);
				cp.setSize(getSize());
				cp.setLocation(0, 0);
			}
		});

		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String x = JOptionPane.showInputDialog("Enter the Point",
						"Enter the point x,y");
				try {
					String[] y = x.split(",");
					double xP = Double.parseDouble(y[0]);
					double xY = Double.parseDouble(y[1]);
					Point p = new Point(xP, xY);
					points.add(p);
				} catch (Exception e) {
					// TODO: handle exception
					JOptionPane.showMessageDialog(null, "Invalid Input");
					return;
				}
				textPane.setText(textPane.getText() + "\n" + "(" + x + ")");
			}
		});
		Component[] cmps = this.getContentPane().getComponents();
		for (Component c : cmps) {
			c.addKeyListener(new KeyListener() {
				@Override
				public void keyTyped(KeyEvent arg0) {
					// TODO Auto-generated method stub
				}

				@Override
				public void keyReleased(KeyEvent arg0) {
					// TODO Auto-generated method stub
				}

				@Override
				public void keyPressed(KeyEvent key) {
					if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
						setBounds(100, 100, 672, 501);
						cp.setLocation(10, 26);
						cp.setSize(490, 420);
					}

				}
			});
		}

	}
}
